package com.atguigu.ssyx.activity.service.impl;


import com.atguigu.ssyx.activity.mapper.ActivityInfoMapper;
import com.atguigu.ssyx.activity.mapper.ActivityRuleMapper;
import com.atguigu.ssyx.activity.mapper.ActivitySkuMapper;
import com.atguigu.ssyx.activity.service.ActivityInfoService;
import com.atguigu.ssyx.activity.service.CouponInfoService;
import com.atguigu.ssyx.client.product.ProductFeignClient;
import com.atguigu.ssyx.enums.ActivityType;
import com.atguigu.ssyx.model.activity.ActivityInfo;
import com.atguigu.ssyx.model.activity.ActivityRule;
import com.atguigu.ssyx.model.activity.ActivitySku;
import com.atguigu.ssyx.model.activity.CouponInfo;
import com.atguigu.ssyx.model.order.CartInfo;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.vo.activity.ActivityRuleVo;
import com.atguigu.ssyx.vo.order.CartInfoVo;
import com.atguigu.ssyx.vo.order.OrderConfirmVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 活动表 服务实现类
 * </p>
 *
 * @author atguigu
 * @since 2025-09-17
 */
@Service
public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, ActivityInfo> implements ActivityInfoService {
    @Autowired
    private ActivityRuleMapper activityRuleMapper;
    @Autowired
    private ActivitySkuMapper activitySkuMapper;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private CouponInfoService couponInfoService;
    //获取活动列表
    @Override
    public IPage<ActivityInfo> selectPage(Page<ActivityInfo> pageparam) {
        IPage<ActivityInfo> activityInfoPage = baseMapper.selectPage(pageparam, null);
        //分页查询对象里面获取列表数据
        List<ActivityInfo> activityInfoList = activityInfoPage.getRecords();
        //遍历activityInfoList集合，获取每一个activityInfo对象
        //向activityInfo对象封装活动类型得到activityTypeString属性里面
        activityInfoList.stream().forEach(item->{
            item.setActivityTypeString(item.getActivityType().getComment());
        });
        return activityInfoPage;
    }

    @Override
    public Map<String, Object> findActivityRuleList(Long id) {
        Map<String, Object> result = new HashMap<String, Object>();
        //根据活动id进行查询，查询activity_role
        LambdaQueryWrapper<ActivityRule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ActivityRule::getActivityId, id);
        List<ActivityRule> activityRuleList = activityRuleMapper.selectList(queryWrapper);
        result.put("activityRuleList", activityRuleList);
        //根据活动id进行查询，查询activity_sku
       LambdaQueryWrapper<ActivitySku> querySkuWrapper = new LambdaQueryWrapper<>();
       querySkuWrapper.eq(ActivitySku::getActivityId, id);
       List<ActivitySku> activitySkuList = activitySkuMapper.selectList(querySkuWrapper);
       //查询出所有的skuid
        List<Long> skuIdlist = activitySkuList.stream().map(ActivitySku::getSkuId).collect(Collectors.toList());
        
        //根据远程调用service_product接口,根据skuid列表获得商品信息
        List<SkuInfo> skuInfoList = productFeignClient.findSkuInfoList(skuIdlist);
        result.put("skuInfoList", skuInfoList);
        return result;
    }

    @Override
    public void saveActivityRule(ActivityRuleVo activityRuleVo) {
        //根据活动id先删除之前的规则数据
        Long activityId = activityRuleVo.getActivityId();
        //ActivityRule数据删除
        activityRuleMapper.delete(
                new LambdaQueryWrapper<ActivityRule>().eq(ActivityRule::getActivityId,activityId)
        );
        //ActivitySku数据删除
        activitySkuMapper.delete(
                new LambdaQueryWrapper<ActivitySku>().eq(ActivitySku::getActivityId, activityId)
        );

        //获取规则列表数据
        List<ActivityRule> activityRuleList = activityRuleVo.getActivityRuleList();
        ActivityInfo activityInfo = baseMapper.selectById(activityId);
        for (ActivityRule activityRule : activityRuleList) {
            activityRule.setActivityId(activityId);
            activityRule.setActivityType(activityInfo.getActivityType());
            activityRuleMapper.insert(activityRule);
        }
        //获取规则范围数据
        List<ActivitySku> activitySkuList = activityRuleVo.getActivitySkuList();
        for (ActivitySku activitySku : activitySkuList) {
            activitySku.setActivityId(activityId);
            activitySkuMapper.insert(activitySku);
        }
    }
    //根据关键字来查询他匹配的sku信息
    @Override
    public List<SkuInfo> findSkuInfoByKeyword(String keyword) {
        //第一步 根据关键字查询sku匹配的内容列表
        //需要远程调用
        //1.在service-product创建接口 根据 关键字查询sku匹配的内容列表
        //2.在service-product-client里面注册接口
        //3.就是在service-activity里面引入依赖
        //4.就是在activity的service层进行服务的注入
        //5.在service-activity远程调用得到sku内容列表
        List<SkuInfo> skuInfoList = productFeignClient.findSkuInfoByKeyword(keyword);
        if(skuInfoList==null||skuInfoList.isEmpty()){
            return skuInfoList;
        }
        //将skuinfolist的所有skuid取到
        List<Long> skuIdList = skuInfoList.stream().map(SkuInfo::getId).collect(Collectors.toList());


        //第二步 判断添加商品之前是否参加过活动，如果之前参加过，活动正在进行中，排除商品
        //1.查询两张表判断activity_info和activity_sku 编写sql语句实现
        List<Long> existSkuIdList= baseMapper.selectSkuIdListExist(skuIdList);
        //2.判断处理 排除已经参加活动的商品
        List<SkuInfo> finnalskuInfoList = new ArrayList<SkuInfo>();
        for (SkuInfo skuInfo : skuInfoList) {
            if (!existSkuIdList.contains(skuInfo.getId())) {
                finnalskuInfoList.add(skuInfo);
            }
        }
        //第三步

        return finnalskuInfoList;
    }
//根据skuId列表获取促销信息
    @Override
    public Map<Long, List<String>> findActivity(List<Long> skuIdList) {
        Map<Long, List<String>> result = new HashMap<>();
        //遍历skuidlist 得到每一个skuid
        skuIdList.forEach(skuId->{
         //根据skuid进行查询 查询sku对应活动里面的规则列表
          List<ActivityRule>  activityRuleList =
                  baseMapper.findActivityRule(skuId);
         //数据封装 规则名称
         if(!CollectionUtils.isEmpty(activityRuleList)){
             List<String> ruleList = new ArrayList<>();
             //把规则的名称处理一下
             for(ActivityRule activityRule:activityRuleList){
                 ruleList.add(this.getRuleDesc(activityRule));
             }
             result.put(skuId, ruleList);
         }
        });

        return result;
    }
//根据skuId列表获取促销数据和优惠卷数据
    @Override
    public Map<String, Object> findActivityAndCoupon(Long skuId, Long userId) {

        //1.根据skuid获取sku营销活动，一个活动里面有多个规则  //这里有错误
        List<ActivityRule> activityRuleList = this.findActivityRuleListBySkuId(skuId);
//        List<ActivityRule> activityRule = baseMapper.findActivityRule(skuId);

        //2.根据skuid和userid查询优惠卷信息
        List<CouponInfo> couponInfoList=couponInfoService.findCouponInfoList(skuId,userId);
        //封装数据到map集合
        Map<String, Object> result = new HashMap<>();
        result.put("couponInfoList", couponInfoList);
        result.put("activityRuleList", activityRuleList);
        return result;
    }

    @Override
    public List<ActivityRule> findActivityRuleListBySkuId(Long skuId) {

        List<ActivityRule> activityRuleList = baseMapper.findActivityRule(skuId);
        for (ActivityRule activityRule : activityRuleList) {
            String ruleDesc = this.getRuleDesc(activityRule);
            activityRule.setRuleDesc(ruleDesc);
        }
        return activityRuleList;
    }
    //获取购物车里面满足条件优惠卷和活动的信息
    @Override
    public OrderConfirmVo findCartActivityAndCoupon(
            List<CartInfo> cartInfoList,
            Long userId) {
        //1获取购物车，每一个购物项参与活动，根据活动规则分组
        //一个规则对应多个商品
        //CartInfoVo
        List<CartInfoVo> cartInfoVoList
                = this.findCartActivityList(cartInfoList);
        //2 计算商品参与活动之后金额
        BigDecimal activityreduceAmount = cartInfoVoList.stream().filter(
                cartInfoVo -> cartInfoVo.getActivityRule() != null
        ).map(
                cartInfoVo -> cartInfoVo.getActivityRule().getReduceAmount()
        ).reduce(
                BigDecimal.ZERO, BigDecimal::add
        );
        //3.获取购物车里面可用使用优惠卷列表
        List<CouponInfo> couponInfoList =
                couponInfoService.findCartCouponInfo(cartInfoList,userId);
        
        //4.计算商品使用优惠卷之后金额，一次只能使用一张优惠卷
        BigDecimal couponReduceAmount = new BigDecimal(0) ;
        if(!CollectionUtils.isEmpty(couponInfoList)){
            couponReduceAmount = couponInfoList.stream().filter(
                    couponInfo -> couponInfo.getIsOptimal().intValue() == 1
            ).map(
                    couponInfo -> couponInfo.getAmount()
            ).reduce(
                    BigDecimal.ZERO, BigDecimal::add
            );
        }
        //5.计算没有参与活动，没有使用优惠卷原始金额
        BigDecimal originalTotalAmount = cartInfoList.stream().filter(
                cartInfo -> cartInfo.getIsChecked().intValue() == 1
        ).map(
                cartInfo -> cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum()))
        ).reduce(BigDecimal.ZERO, BigDecimal::add);
        //6.参与了活动，使用优惠卷总金额
        BigDecimal totalAmount = originalTotalAmount.subtract(activityreduceAmount).subtract(couponReduceAmount);
        //7，封装需要数据到OrderConfirmVo 返回
        OrderConfirmVo orderTradeVo = new OrderConfirmVo();
        orderTradeVo.setCarInfoVoList(cartInfoVoList);
        orderTradeVo.setActivityReduceAmount(activityreduceAmount);
        orderTradeVo.setCouponInfoList(couponInfoList);
        orderTradeVo.setCouponReduceAmount(couponReduceAmount);
        orderTradeVo.setOriginalTotalAmount(originalTotalAmount);
        orderTradeVo.setTotalAmount(totalAmount);
        return orderTradeVo;
    }
    //获取购物车对应规则数据
    @Override
    public List<CartInfoVo> findCartActivityList(List<CartInfo> cartInfoList) {
        //创建最终返回集合
        List<CartInfoVo> cartInfoVoList = new ArrayList<>();
        //获取所有的skuId
        List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).collect(Collectors.toList());
        //根据所有的skuid列表获取到参与活动
        List<ActivitySku> activitySkuList=baseMapper.selectCartActivity(skuIdList);
        //对数据分组（根据活动进行分组，每一个活动里面有哪些sku的id）
        //下面map里面的key是分组的字段，活动id
        //value是每组里面sku列表的数据，set集合不重复
        Map<Long, Set<Long>> activityIdToSkuIdListMap = activitySkuList.stream()
                .collect(
                        Collectors.groupingBy(
                                ActivitySku::getActivityId,
                                Collectors.mapping(ActivitySku::getSkuId, Collectors.toSet())
                        )
                );
        //获取活动里面规则的数据
        //key是活动id value 是活动里面规则列表数据
        Map<Long,List<ActivityRule>> activityIdToActivityRuleListMap
                = new HashMap<>();
        //获取所有活动id
        Set<Long> activityIdSet = activitySkuList.stream().map(ActivitySku::getActivityId).collect(Collectors.toSet());
        if(!CollectionUtils.isEmpty(activityIdSet)){
            //activity_rule表
            LambdaQueryWrapper<ActivityRule> activityRuleLambdaQueryWrapper = new LambdaQueryWrapper<>();
            activityRuleLambdaQueryWrapper.orderByDesc(ActivityRule::getConditionAmount,ActivityRule::getConditionNum);
            activityRuleLambdaQueryWrapper.in(ActivityRule::getActivityId, activityIdSet);
            List<ActivityRule> activityRuleList = activityRuleMapper.selectList(activityRuleLambdaQueryWrapper);
            //封装到activityIdToActivityRuleListMap里面
            //根据活动id分组
            activityIdToActivityRuleListMap = activityRuleList.stream().collect(
                    Collectors.groupingBy(activityRule -> activityRule.getActivityId())
            );
        }
        //有活动的购物项skuId
        Set<Long> activitySkuIdSet = new HashSet<>();
        if(!CollectionUtils.isEmpty(activityIdToSkuIdListMap)){
            //遍历activityIdToSkuIdListMap集合
            Iterator<Map.Entry<Long, Set<Long>>> iterator = activityIdToSkuIdListMap.entrySet().iterator();
            while(iterator.hasNext()){
                Map.Entry<Long, Set<Long>> entry = iterator.next();
                //activityId 活动id
                Long activityId = entry.getKey();
                //每一个活动对应的skuId列表
                Set<Long> currentActivitySkuIdSet = entry.getValue();

                //获取当前活动购物项的列表
                List<CartInfo> currentActivityCartInfoList = cartInfoList.stream()
                        .filter(cartInfo -> currentActivitySkuIdSet.contains(cartInfo.getSkuId()))
                        .collect(Collectors.toList());

                //计算购物项总的金额和总的数量
                BigDecimal activityTotalAmount =
                        this.computeTotalAmount(currentActivityCartInfoList);
                int activityTotalNum = this.computeCartNum(currentActivityCartInfoList);

                //计算活动对应规则
                //根据activityId获取活动的对应规则
                List<ActivityRule> CurrentActivityRuleList
                        = activityIdToActivityRuleListMap.get(activityId);
                ActivityType activityType = CurrentActivityRuleList.get(0).getActivityType();
                //判断活动类型:满减还是打折
                ActivityRule activityRule = null;
                if(activityType == ActivityType.FULL_REDUCTION){//满减
                    activityRule = this.computeFullReduction(activityTotalAmount, CurrentActivityRuleList);
                }else{//满量
                    activityRule  =this.computeFullDiscount(activityTotalNum,activityTotalAmount,CurrentActivityRuleList);
                }
                //cartInfoVo封装
                CartInfoVo cartInfoVo = new CartInfoVo();
                cartInfoVo.setActivityRule(activityRule);
                cartInfoVo.setCartInfoList(currentActivityCartInfoList);
                cartInfoVoList.add(cartInfoVo);
                //记录一下哪些购物项参与活动
                activitySkuIdSet.addAll(currentActivitySkuIdSet);
            }
        }
        //没有活动购物项skuId
        //获取哪些skuId没有参加活动
        skuIdList.removeAll(activitySkuIdSet);
        if(!CollectionUtils.isEmpty(skuIdList)){
            Map<Long, CartInfo> skuIdCartInfoMap = cartInfoList.stream().collect(
                    Collectors.toMap(CartInfo::getSkuId, CartInfo -> CartInfo)
            );
            for(Long skuId:skuIdList){
                CartInfoVo cartInfoVo = new CartInfoVo();
                cartInfoVo.setActivityRule(null);//没有活动

                List<CartInfo> cartInfos = new ArrayList<>();
                cartInfos.add(skuIdCartInfoMap.get(skuId));
                cartInfoVo.setCartInfoList(cartInfos);

                cartInfoVoList.add(cartInfoVo);
            }
        }
        return cartInfoVoList;
    }
    /**
     * 计算满量打折最优规则
     * @param totalNum
     * @param activityRuleList //该活动规则skuActivityRuleList数据，已经按照优惠折扣从大到小排序了
     */
    private ActivityRule computeFullDiscount(Integer totalNum, BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
        ActivityRule optimalActivityRule = null;
        //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
        for (ActivityRule activityRule : activityRuleList) {
            //如果订单项购买个数大于等于满减件数，则优化打折
            if (totalNum.intValue() >= activityRule.getConditionNum()) {
                BigDecimal skuDiscountTotalAmount = totalAmount.multiply(activityRule.getBenefitDiscount().divide(new BigDecimal("10")));
                BigDecimal reduceAmount = totalAmount.subtract(skuDiscountTotalAmount);
                activityRule.setReduceAmount(reduceAmount);
                optimalActivityRule = activityRule;
                break;
            }
        }
        if(null == optimalActivityRule) {
            //如果没有满足条件的取最小满足条件的一项
            optimalActivityRule = activityRuleList.get(activityRuleList.size()-1);
            optimalActivityRule.setReduceAmount(new BigDecimal("0"));
            optimalActivityRule.setSelectType(1);

            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionNum())
                    .append("元打")
                    .append(optimalActivityRule.getBenefitDiscount())
                    .append("折，还差")
                    .append(totalNum-optimalActivityRule.getConditionNum())
                    .append("件");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
        } else {
            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionNum())
                    .append("元打")
                    .append(optimalActivityRule.getBenefitDiscount())
                    .append("折，已减")
                    .append(optimalActivityRule.getReduceAmount())
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
            optimalActivityRule.setSelectType(2);
        }
        return optimalActivityRule;
    }

    /**
     * 计算满减最优规则
     * @param totalAmount
     * @param activityRuleList //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
     */
    private ActivityRule computeFullReduction(BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
        ActivityRule optimalActivityRule = null;
        //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
        for (ActivityRule activityRule : activityRuleList) {
            //如果订单项金额大于等于满减金额，则优惠金额
            if (totalAmount.compareTo(activityRule.getConditionAmount()) > -1) {
                //优惠后减少金额
                activityRule.setReduceAmount(activityRule.getBenefitAmount());
                optimalActivityRule = activityRule;
                break;
            }
        }
        if(null == optimalActivityRule) {
            //如果没有满足条件的取最小满足条件的一项
            optimalActivityRule = activityRuleList.get(activityRuleList.size()-1);
            optimalActivityRule.setReduceAmount(new BigDecimal("0"));
            optimalActivityRule.setSelectType(1);

            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionAmount())
                    .append("元减")
                    .append(optimalActivityRule.getBenefitAmount())
                    .append("元，还差")
                    .append(totalAmount.subtract(optimalActivityRule.getConditionAmount()))
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
        } else {
            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionAmount())
                    .append("元减")
                    .append(optimalActivityRule.getBenefitAmount())
                    .append("元，已减")
                    .append(optimalActivityRule.getReduceAmount())
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
            optimalActivityRule.setSelectType(2);
        }
        return optimalActivityRule;
    }

    private BigDecimal computeTotalAmount(List<CartInfo> cartInfoList) {
        BigDecimal total = new BigDecimal("0");
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if(cartInfo.getIsChecked().intValue() == 1) {
                BigDecimal itemTotal = cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum()));
                total = total.add(itemTotal);
            }
        }
        return total;
    }

    private int computeCartNum(List<CartInfo> cartInfoList) {
        int total = 0;
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if(cartInfo.getIsChecked().intValue() == 1) {
                total += cartInfo.getSkuNum();
            }
        }
        return total;
    }
    //构造规则名称的方法
    private String getRuleDesc(ActivityRule activityRule) {
        ActivityType activityType = activityRule.getActivityType();
        StringBuffer ruleDesc = new StringBuffer();
        if (activityType == ActivityType.FULL_REDUCTION) {
            ruleDesc
                    .append("满")
                    .append(activityRule.getConditionAmount())
                    .append("元减")
                    .append(activityRule.getBenefitAmount())
                    .append("元");
        } else {
            ruleDesc
                    .append("满")
                    .append(activityRule.getConditionNum())
                    .append("元打")
                    .append(activityRule.getBenefitDiscount())
                    .append("折");
        }
        return ruleDesc.toString();
    }

}
